﻿using System;
using PServiceBus.Core.Interface;
using PServiceBus.Core.Runtime;
using System.Net;
using PServiceBus.Core.Runtime.Transports;
using System.Runtime.Serialization;
using System.ComponentModel.Composition;
using PServiceBus.Core.Runtime.Messages;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;

using PServiceBus.Core.Runtime.Extensions;

namespace PServiceBus.Transports {
    [Serializable]
    [DataContract]
    [Export(typeof(ITransport))]
    public class HttpTransport : ITransport {

        [DataMember]
        public string Url { get; set; }
        [DataMember]
        public Dictionary<string, string> QueryParams { get; set; }
        [DataMember]
        public Dictionary<string, string> Headers { get; set; }
        [DataMember]
        public int? ContentLength { get; set; }
        [DataMember]
        public bool Async { get; set; }

        #region ITransport Members
        [DataMember]
        public TransportFormat Format { get; set; }

        [MessageShark.MessageSharkIgnore]
        private MessageMapper _messageMapper;

        public TransportResponse Send(string message, Dictionary<string, object> messageStructure) {
            var tranResponse = TransportResponse.New<HttpTransport>();
            var url = Url + (Url.EndsWith("?") ? string.Empty : "?");
            _messageMapper = MessageMapper.Map(message, messageStructure);
            Headers = Headers ?? new Dictionary<string, string>();
            try {
                if (!Url.Exists()) throw new Exception("Web url does not exist!");
                foreach (var msg in _messageMapper.Tokens) SendHttpRequest(url, msg);
                tranResponse.Success = true;
            } catch(Exception ex) {
                tranResponse.Message = ex.ToString();
            }
            return tranResponse;
        }

        private string Normalize(string text) {
            return text;//.Replace("<", "&lt;").Replace(">", "&gt;").Replace("?", "&#63;").Replace("&", "&amp;");
        }

        private void SendHttpRequest(string url, MessageMapperToken message) {
            var query =
                 String.Join("&", QueryParams.Select(param =>
                        String.Format("{0}={1}", HttpUtility.UrlEncode(param.Key),
                        HttpUtility.UrlEncode(Normalize(message[param.Value])))));
            var queryBytes = Encoding.UTF8.GetBytes(query);
            var request = WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = Math.Max((ContentLength ?? 0), queryBytes.Length);
            if (Headers.Count > 0) {
                request.Headers = new WebHeaderCollection();
                foreach (var header in Headers) request.Headers[header.Key] = header.Value;
            }

            if (!Async) {
                using (var requestStream = request.GetRequestStream()) {
                    requestStream.Write(queryBytes, 0, queryBytes.Length);
                    requestStream.Flush();
                }
                var response = request.GetResponse();
                response.Close();
            } else {
                request.BeginGetRequestStream(r =>
                {
                    var buffer = r.AsyncState as byte[];
                    var rs = request.EndGetRequestStream(r);
                    rs.BeginWrite(buffer, 0, buffer.Length, r2 =>
                    {
                        rs.EndWrite(r2);
                        rs.Flush();

                        request.BeginGetResponse(r3 =>
                        {
                            var res = request.EndGetResponse(r3);
                            res.Close();
                        }, null);
                    }, null);
                }, queryBytes);
            }
        }
        #endregion
    }
}
